AWS IoT SiteWise Monitor で複数デバイスのセンサーデータを可視化してみた
以前の記事では、単一デバイスのデータを SiteWise Monitor で可視化しました。
もちろん複数デバイスのセンサーデータも可視化することができますが、アセットモデルの作り方に注意が必要なので、その方法をご紹介したいと思います。
アセットとアセットモデル
最初に、簡単にアセットとアセットモデルについて確認しておきましょう。
公式ドキュメントは下記になります。
AWS IoT SiteWise では「個々の機器」や「個々の工場」、「プラント全体」などを「アセット」という単位で表現することができます。
また、これらのアセットは個々に様々なデータを持ちます。例えば 発電機なら「発電量」「温度」「回転数」などです。工場全体で見ると個々の工場ごとに「合計発電量」「平均回転数」などのデータを持つことが考えられます。これらのアセットを構成する要素をアセットプロパティと呼びます。
上記のような動的なデータは「測定値」というプロパティになります。 アセットプロパティのその他の種類として「デバイスの型番などの静的な属性」や 「華氏を摂氏に変換した計算値」、「データの平均値といったメトリクス」も定義することが可能です。
このように各アセットのデータ構造を定義するフォーマットがアセットモデルです。アセットのテンプレートと考えると分かりやすいです。
下記はアセットとアセットモデルのイメージ図です。
またアセットモデルは階層的に構成することもできます。例えば、「個々の機器」「個々の工場」「全ての工場」という形で階層化して、デバイス単位、工場単位、全工場という単位別にデータを管理・可視化することができます。
階層化されたアセットを可視化する
前回は単一のデバイスに対して SiteWise Monitor で可視化しました。
先程のように図にすると下記のようなイメージです。
単一デバイスのときは特に問題なく可視化できますが、SiteWise Monitor のダッシュボードに登録できるのは「単一のアセットのみ」です。そのため複数のアセットをダッシュボードに登録できません。
これを解決するために、アセットモデルを階層化して最上位のアセットをダッシュボードに登録することで全体を可視化することができるようになります。
疑似デバイスデータで試してみる
アセット、アセットモデル、モデルの階層化について概念が理解できたので、実際に擬似的なデバイスを用意して作業をしていきます。今回作成する全体像は下記の様になります。
アーキテクチャは下記のとおりです。今回も SiteWise API を使って擬似的なデバイスデータを SiteWise に書き込みます。
アセット、アセットモデル、階層化の作成
まずは下位のアセットモデルを作成しましょう。このモデルは個々のデバイスを定義するアセットモデルになります。(Test Device
という名前で作成しました)
「測定の定義」で clock
と temperature
を図の通り作成します。
次にアセットを作成します。アセットモデルは先程作成した Test Device
です。
今回は 2つのデバイス用のアセットを作成します。1つ目は test-device-1
というアセットです。
同じように test-device-2
というアセットを作成します。
次に上位のアセットモデルを作成します。今回は All Device
という名前で作成しました。
「階層の定義」 で階層関係を設定します。下記のように適当な階層名を付けて「階層モデル」ではプルダウンから下位のモデルとして作成した Test Device
を選択します。
モデルが作成できたので次にアセット All Device
を作成します。
先程作成したアセット All Device
ができたら「編集」をクリックしてアセットの関連付けを行います。
下記のように、このアセットに関連付ける下位のアセットを指定します。「階層」には先程作成したものを選択します。また、今回は2つのデバイス test-device-1
と test-device-2
を関連付けます。
ここまで作業が終われば、下記のようにアセットが階層化された状態で表示されるようになります。
ポータルの作成
次にデータを可視化するためのポータルを作成します。
適当なポータル名(今回は AllDevices
)を設定します。「ユーザー認証」は前回と同様に「IAM」を選択しました。
「サポート連絡先のEメール」は適当なものをセットして下さい。
「アクセス許可」のロールは新規作成することにします。
次のオプションでは、前回同様に「アラームの有効化」と「エッジ設定」を無効にしておきます。
管理者も前回同様に既存の IAM Role を選択しました。
ユーザーは未設定のままとしました。
(検証で利用者が私しかいないので)
AllDevices
というポータルが作成できました。
ダッシュボードの作成
ポータルができたので「ポータルを開く」をクリックして SiteWise Monitor に移動します。
モニターの画面でも階層化されたアセットが見えていることを確認できます。
最初に説明した通り、「ダッシュボードには 1 つのアセットしか登録できない」ので、最上位のアセットモデルのアセットである All Device
を選択して「プロジェクトにアセットを追加」をクリックします。
All Device
を選択して「次へ」をクリックします。
新しいプロジェクト名を付けてプロジェクトを作成します。これでアセットが追加された状態でプロジェクトが作成されます。
プロジェクトを作成すると、そのプロジェクト画面が開いた状態になるので、そのまま「ダッシュボードを作成」をクリックしてグラフ配置を作成していきます。
前回のようにアセットを選択して、ダッシュボード中央にドラッグ&ドロップでグラフを配置していきます。
下記のように test-device-1
と test-debice-2
の両方のアセット(計 4 つ)が配置できました。
まだデータが来ていないのでグラフには何もプロットされていません。
データの書込み
次のコードを使って 2つのデバイスを模した擬似的なセンサーデータを書込みます。
import boto3 import uuid import random import time import logging import sys import json import math import threading logger = logging.getLogger() logger.setLevel(logging.INFO) streamHandler = logging.StreamHandler(stream=sys.stdout) formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') streamHandler.setFormatter(formatter) logger.addHandler(streamHandler) client = boto3.client('iotsitewise') def batch_put_asset(device_id): start = time.time() mode = 'low' # 最初はLOWモードでスタートすることにする logger.info("starting low mode... ") while True: timer = int(time.time() - start) # 現在時刻の取得 (小数部, 整数部) # https://note.nkmk.me/python-math-modf/ timestamp_float, timestamp_int = math.modf(time.time()) if mode == 'low': if timer < 10: MeasureValueTemp = random.uniform(1, 30) MeasureValueClock = random.randint(600000000,800000000) #print('mode low') logger.info("temperature: {}".format(MeasureValueTemp)) logger.info("clock: {}".format(MeasureValueClock)) else: mode = 'high' logger.info("starting high mode... ") start = time.time() + 1 # reset timer #start = time.time() continue else: #if mode == 'high': if timer < 10: # Mode: High load MeasureValueTemp = random.uniform(50, 90) MeasureValueClock = random.randint(1200000000,1500000000) #print('mode high') logger.info("temperature: {}".format(MeasureValueTemp)) logger.info("clock: {}".format(MeasureValueClock)) else: mode = 'low' logger.info("starting low mode... ") #print(str(int(time.time())) + ' start low mode...') start = time.time() + 1 # reset timer #start = time.time() continue try: response = client.batch_put_asset_property_value( entries=[ { 'entryId': '{}'.format(uuid.uuid4()), 'propertyAlias': '/test/device/{}/temperature'.format(device_id), 'propertyValues': [ { 'value': { 'doubleValue': MeasureValueTemp }, 'timestamp': { 'timeInSeconds': int(timestamp_int), 'offsetInNanos': int(round((timestamp_float * 1000000000), 0)) }, 'quality': 'GOOD' }, ] }, { 'entryId': '{}'.format(uuid.uuid4()), 'propertyAlias': '/test/device/{}/clock'.format(device_id), 'propertyValues': [ { 'value': { 'doubleValue': MeasureValueClock }, 'timestamp': { 'timeInSeconds': int(timestamp_int), 'offsetInNanos': int(round((timestamp_float * 1000000000), 0)) }, 'quality': 'GOOD' }, ] }, ] ) logger.info("response: {}\n".format(json.dumps(response, indent=2))) logger.info("propertyAlias: {}\n".format(device_id)) if response['errorEntries']: logger.error("temperature: {} clock: {}".format(MeasureValueTemp, MeasureValueClock)) #else: # logger.info("temperature: {} clock: {}".format(MeasureValueTemp, MeasureValueClock)) except Exception as e: logger.error("{}".format(e)) logger.error("temperature: {} clock: {}".format(MeasureValueTemp, MeasureValueClock)) time.sleep(5) device_1 = threading.Thread(target=batch_put_asset,args=(1,)) device_2 = threading.Thread(target=batch_put_asset,args=(2,)) device_1.start() device_2.start()
上記コードを実行する環境に対して、SiteWise に書込みできる権限 を付与しておきます。
付与する IAM 権限は下記のとおりですが、緩い内容になっているので本番用途で利用する際はさらに権限を絞って設定して下さい。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": "iotsitewise:BatchPutAssetPropertyValue", "Resource": "*" } ] }
スクリプトを実行して書込みをスタートします。
$ python sitewise-send-data-api-thread.py
アセットプロパティとデータストリームの関連付け
データの書込みが正常に行えていれば、SiteWise のコンソールにある「データストリーム」の画面で、下記のように4つの「データストリームエイリアス」が表れています。
4 つ全てを選択して「データストリームを管理」をクリックして、アセットプロパティと関連付けていきます。
最初にデータストリームエイリアス /test/device/1/temperature
の「測定値を選択」をクリックします。
次に、対応するアセット test-device-1
を展開して、このエイリアスに対応する測定値 temperature
を選択します。
最後に左上の「選択」をクリックします。
/test/device/1/clock
に対しても同じ手順で関連付けを行います。
test-device-2
についても同じ手順を繰り返します。
全ての関連付けが完了したら下記のようになっているはずなので、最後に「更新」をクリックして設定を確定します。
正しく関連付けていることが分かります。
ダッシュボードの変更
データの関連付けができれば下記のようにダッシュボードにもデータが反映されているはずです。
これで、全デバイスのデータを1つのダッシュボードで可視化することができました。
このままでも問題ないですが、グラフが4つに分散していて見づらいので同じ種類のグラフをまとめてみたいと思います。
グラフの描画設定を変更するには画面右上の「編集」をクリックします。
まず、test-device-2
のグラフを全部(clock
と temperature
)一旦削除します。
次に test-device-1
の clock
のグラフを temperature
グラフの下側に移動させます。
両方のグラフの大きさを合わせておきます。
次に、削除した test-device-2
のグラフを再度追加します。追加するときに既存のグラフ上に別のグラフを重ねることで 1 つの領域で複数のグラフを描画することができます。
これで、clock
と temperature
という種類別に2つのデバイスをまとめてグラフ化できました。
グラフの名前も変更しておきましょう。
変更を保存したら下記のようなグラフになりました。2つのデバイスデータを直感的に比較できるようになり見やすくなりました。
最後に
今回は複数データの可視化と、そのために必要となるアセットモデルの階層化についてご紹介しました。
「どのようなデータをどのように可視化したいのか」をしっかりイメージして階層を作ることがポイントになります。
以上です。